/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
 * Description: Parse sps information from avc data
 * Author: HiMobileCam middleware develop team
 * Create: 2017-12-22
 */

#include "ffavcparser.h"

#include "securec.h"
#include "ffbitsreader.h"

static HI_VOID FFAVCParserParseSpsReadScalingMatrix(FfBitReader *bitsReader, const AvcSpsInfo *spsInfo)
{
    HI_U32 count = ((spsInfo->chromaFormatIdc != 3) ? 8 : 12);
    for (HI_U32 i = 0; i < count; i++) {
        HI_U8 seqScalingListFlag = FfBitReadU1(bitsReader);
        if (!seqScalingListFlag) {
            continue;
        }
        HI_U8 lastScale = 8;
        HI_U8 nextScale = 8;
        HI_U32 scaletimes = (i < 6) ? 16 : 64;
        for (HI_U32 j = 0; j < scaletimes; j++) {
            if (nextScale != 0) {
                HI_U32 deltaScale = FfBitReadSeV(bitsReader);
                nextScale = (lastScale + deltaScale + 256) % 256;
            }
            HI_U8 scaleListJ = (nextScale == 0) ? lastScale : nextScale;
            lastScale = scaleListJ;
        }
    }
}

/* h264  7.3.2.1.1   T-REC-H.264-201602-S!!PDF-E.pdf */
HI_BOOL FFAVCParserParseSps(AvcSpsInfo *outSpsInfo, const HI_U8 *sps, HI_U32 spsSize)
{
    if ((outSpsInfo == HI_NULL) || (sps == HI_NULL) || (spsSize == 0)) {
        return HI_FALSE;
    }

    FfBitReader *bitsReader = HI_NULL;
    HI_S32 ret = FFBitsReaderCreate(&bitsReader, sps, spsSize);
    if (ret != HI_SUCCESS) {
        return HI_FALSE;
    }

    AvcSpsInfo spsInfo = { 0 };
    FfBitReadU8(bitsReader);                       // 0x67 nal type
    HI_U8 profileIdc = FfBitReadU8(bitsReader);  // profile_idc
    FfBitReadU8(bitsReader);                       // constraint_setx_flag
    FfBitReadU8(bitsReader);                       // level_idc
    FfBitReadUeV(bitsReader);                      // seq_parameter_set_id
    if ((profileIdc == 100) || (profileIdc == 110) || (profileIdc == 122) ||
        (profileIdc == 244) || (profileIdc == 44) || (profileIdc == 83) ||
        (profileIdc == 86) || (profileIdc == 118) || (profileIdc == 128) ||
        (profileIdc == 138) || (profileIdc == 139) || (profileIdc == 134) ||
        (profileIdc == 135)) {
        spsInfo.chromaFormatIdc = FfBitReadUeV(bitsReader);
        if (spsInfo.chromaFormatIdc == 3) {
            FfBitReadU1(bitsReader);  // separate_colour_plane_flag
        }
        FfBitReadUeV(bitsReader);                                // bits_depth_luma_minus8
        FfBitReadUeV(bitsReader);                                // bits_depth_chroma_minus8
        FfBitReadU1(bitsReader);                                 // qpprime_y_zero_transform_bypass_flag
        HI_U8 seqScalingMatrixFlag = FfBitReadU1(bitsReader);  // seq_scaling_matrix_present_flag
        if (seqScalingMatrixFlag) {
            FFAVCParserParseSpsReadScalingMatrix(bitsReader, &spsInfo);
        }
    }
    FfBitReadUeV(bitsReader);  // log2_max_frame_num_minus4
    HI_U32 picOrderCntType = FfBitReadUeV(bitsReader);
    if (picOrderCntType == 0) {
        FfBitReadUeV(bitsReader);  // log2_max_pic_order_cnt_lsb_minus4
    } else if (picOrderCntType == 1) {
        FfBitReadU1(bitsReader);                                           // delta_pic_order_always_zero_flag
        FfBitReadSeV(bitsReader);                                          // offset_for_non_ref_pic
        FfBitReadSeV(bitsReader);                                          // offset_for_top_to_bottom_field
        HI_U32 numRefFramesInPicOrderCntCycle = FfBitReadUeV(bitsReader);  // num_ref_frames_in_pic_order_cnt_cycle
        for (HI_U32 i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
            FfBitReadSeV(bitsReader);  // offset_for_ref_frame[i]
        }
    }
    FfBitReadUeV(bitsReader);                                          // max_num_ref_frames
    FfBitReadU1(bitsReader);                                           // gaps_in_frame_num_value_allowed_flag
    spsInfo.picWidthInMbsMinus1 = FfBitReadUeV(bitsReader);        // pic_width_in_mbs_minus1
    spsInfo.picHeightInMapUnitsMinus1 = FfBitReadUeV(bitsReader);  // pic_height_in_map_units_minus1
    spsInfo.frameMbsOnlyFlag = FfBitReadU1(bitsReader);              // frame_mbs_only_flag
    // no useful data behind
    if (!spsInfo.frameMbsOnlyFlag) {
        spsInfo.adaptFrameFlieFlag = FfBitReadU1(bitsReader);  // mb_adaptive_frame_field_flag
    }
    spsInfo.directInferenceFlag = FfBitReadU1(bitsReader); /* direct_8x8_inference_flag : 1 */
    spsInfo.fameCroppingFlag = FfBitReadU1(bitsReader);    /* frame_cropping_flag : 1 */
    if (spsInfo.fameCroppingFlag) {
        spsInfo.frameCropLeftOffset = FfBitReadUeV(bitsReader);   /* frame_crop_left_offset : 0 */
        spsInfo.frameCropRightOffset = FfBitReadUeV(bitsReader);  /* frame_crop_right_offset : 0 */
        spsInfo.frameCropTopOffset = FfBitReadUeV(bitsReader);    /* frame_crop_top_offset : 0 */
        spsInfo.frameCropBottomOffset = FfBitReadUeV(bitsReader); /* frame_crop_bottom_offset : 4 */
    }

    if (memcpy_s(outSpsInfo, sizeof(AvcSpsInfo), &spsInfo, sizeof(AvcSpsInfo)) != EOK) {
        FFBitsReaderDestroy(bitsReader);
        return HI_FALSE;
    }
    FFBitsReaderDestroy(bitsReader);
    return HI_TRUE;
}
